package love.xiaohh.minio.services.impl;

import io.minio.*;
import io.minio.errors.*;
import love.xiaohh.minio.config.MinioProperties;
import love.xiaohh.minio.services.MinioService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * <p>
 * 文件系统的服务层实现
 * </p>
 *
 * @author XiaoHH
 * @version 1.0
 * @date 2021-11-21 星期日 9:35:42
 * @file MinioServiceImpl.java
 */
@Service
public class MinioServiceImpl implements MinioService {

    /**
     * 记录日志的工具
     */
    private static final Logger log = LoggerFactory.getLogger(MinioServiceImpl.class);

    /**
     * minio文件系统的客户端
     */
    private final MinioClient minioClient;

    /**
     * 初始化文件系统
     *
     * @param minioConfig 文件系统的配置
     */
    public MinioServiceImpl(MinioProperties minioConfig) {
        this.minioClient = MinioClient.builder()
                .endpoint(minioConfig.getHost(), minioConfig.getPort(), false)
                .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()).build();
    }

    /**
     * 上传一个文件
     *
     * @param bucket     桶名字
     * @param objectName 对象名字
     * @param file       文件
     */
    @Override
    public void putObject(String bucket, String objectName, MultipartFile file) {
        try {
            this.putObject(bucket, objectName, file.getContentType(), file.getInputStream());
        } catch (IOException e) {
            log.error("上传文件时出错", e);
        }
    }

    /**
     * 上传一个文件
     *
     * @param bucket      桶名字
     * @param objectName  对象名字
     * @param contentType 文件类型
     * @param inputStream 输入流
     */
    @Override
    public void putObject(String bucket, String objectName, String contentType, InputStream inputStream) {
        try {
            // 判断桶是否存在，不存在则创建
            BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucket).build();
            if (!this.minioClient.bucketExists(bucketExistsArgs)) {
                synchronized (this) {
                    if (!this.minioClient.bucketExists(bucketExistsArgs)) {
                        MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucket).build();
                        this.minioClient.makeBucket(makeBucketArgs);
                    }
                }
            }
            // 存入分布式文件系统
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucket).object(objectName).contentType(contentType)
                    .stream(inputStream, inputStream.available(), -1).build();
            this.minioClient.putObject(putObjectArgs);
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidResponseException | InvalidKeyException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
            log.error("上传文件时出错", e);
        }
    }

    /**
     * 获取一个文件对象
     *
     * @param bucket     桶名称
     * @param objectName 对象名称
     * @return 输入流
     */
    @Override
    public GetObjectResponse getObject(String bucket, String objectName) {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucket).object(objectName).build();
        try {
            return this.minioClient.getObject(getObjectArgs);
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
            log.error("获取一个文件对象时出错", e);
        }
        return null;
    }

    /**
     * 获取文件状态
     *
     * @param bucket     桶名称
     * @param objectName 对象名称
     * @return 获取文件状态
     */
    @Override
    public StatObjectResponse getStatObject(String bucket, String objectName) {
        try {
            StatObjectArgs statObjectArgs = StatObjectArgs.builder().bucket(bucket).object(objectName).build();
            return this.minioClient.statObject(statObjectArgs);
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
            log.error("获取文件状态时出错", e);
            return null;
        }
    }

    /**
     * 在分布式文件系统当中删除一个文件
     *
     * @param bucketName 同名称
     * @param objectName 对象名称
     */
    @Override
    public void removeObject(String bucketName, String objectName) {
        try {
            this.minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
            log.error("在分布式文件系统当中删除一个文件时出错", e);
        }
    }
}
